package copyengine.ui.dialog
{
	import copyengine.ui.dialog.animation.ICEDialogAnimation;
	import copyengine.utils.GeneralUtils;

	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.events.MouseEvent;

	import org.as3commons.reflect.Type;

	public class CEDialog
	{
		private var dialogState:int;
		private var dialogAnimation:ICEDialogAnimation;

		//当点击Dialog则会重新AddChild一遍当前的Dialog,将Dialog至于所有Dialog的最上方 
		private var sortCurrentDialogToTopCallBack:Function;
		//当当前DialogDispose时候回调上层函数
		private var dialogDisposeCallBack:Function;

		private var dragToMoveContainer:DisplayObject;
		private var dragToMoveOffsetX:int;
		private var dragToMoveOffsetY:int;

		private var dialogUniqueName:String;

		protected var dialogContainer:Sprite;

		private var allDialogDisposeCallBackVector:Vector.<Function>;

		public function CEDialog()
		{
		}

		//=================================================//
		//==					    			     Public Function                                           ==//
		//=================================================//

		public final function setAnimation(_animation:ICEDialogAnimation):void
		{
			dialogAnimation = _animation;
			dialogAnimation && dialogAnimation.setTarget(this);
		}

		/**
		 *<b>添加 当前Dialog Dispose时候的Callback函数</b>
		 */
		public final function addDialogDisposeCallBack(_f:Function):void
		{
			if (allDialogDisposeCallBackVector == null)
			{
				allDialogDisposeCallBackVector = new Vector.<Function>();
			}
			allDialogDisposeCallBackVector.indexOf(_f) < 0 && allDialogDisposeCallBackVector.push(_f);
		}

		public final function close():void
		{
			if (dialogState == CEDialogConfig.STATE_DISPOSED)
			{
				return;
			}
			else if (dialogState == CEDialogConfig.STATE_OPEN && dialogAnimation)
			{
				dialogState = CEDialogConfig.STATE_DISPOSED;
				dialogAnimation.closeDialog(onCloseDialogAnimationFinished);
			}
			else
			{
				dialogState = CEDialogConfig.STATE_DISPOSED;
				disposeDialog();
			}
		}

		//=================================================//
		//==					    			      Internal Function                                       ==//
		//=================================================//

		internal final function setDialogState(_state:int):void
		{
			dialogState = _state;
		}

		internal final function getDialogState():int
		{
			return dialogState;
		}

		internal final function initDialog():void
		{
			dialogContainer = new Sprite();
		}

		/**
		 * <b>当Screen大小发生改变时候会由CEDialogGroupPopWarp回调该函数</b>
		 * <li>CEDialogGroupPopWarp只会回调已经Pop出来的Dialog
		 */
		internal final function onScreenResize(_currenStageWidth:int,
											   _currentStageHeight:int,
											   _offestWidth:int,
											   _offestHeight:int,
											   _offsetXPercent:Number,
											   _offsetYPercent:Number):void
		{
			doOnScreenResize(_currenStageWidth, _currentStageHeight, _offestWidth, _offestHeight, _offsetXPercent, _offsetYPercent);
		}

		/**
		 *<b>当外部类取得DialogContainer后对其位置进行操作后需要回调该函数，
		 * 通通Dialog进行相应刷新</b>
		 */
		internal final function dialogContainerMoved():void
		{
			doOnDialogContainerMove();
		}

		/**
		 * <b>刷新Dialog的CallBack函数</b>
		 * </br>当Dialog从一个PopWarp中移除时候，有可能被添加到新的PopWarp中，此时就要重新设置CallBackFunction
		 * 否则就调到原有的PopWarp中
		 *
		 * @param _sortCurrentDialogToTopCallBack		点击Sort到最高层的CallBack
		 * @param _dialogDisposeCallBack							Dialog Dispose掉后的回调函数
		 *
		 */
		internal final function refreshCallBackFunction(_sortCurrentDialogToTopCallBack:Function, _dialogDisposeCallBack:Function):void
		{
			sortCurrentDialogToTopCallBack = _sortCurrentDialogToTopCallBack;
			dialogDisposeCallBack = _dialogDisposeCallBack;
		}

		internal final function popup():void
		{
			initialize();
			dragToMoveContainer = getDialogDragToMoveContainer();
			addDialogListener();
			dialogAnimation && dialogAnimation.showDialog(onOpenDialogAnimationFinisehd);
		}

		copyengine_dialog_internal final function getDialogContainer():DisplayObjectContainer
		{
			return dialogContainer;
		}

		internal function disposeDialog():void
		{
			removeDialogListener();
			doDispose();

			while (allDialogDisposeCallBackVector != null &&
				allDialogDisposeCallBackVector.length > 0)
			{
				allDialogDisposeCallBackVector.pop()();
			}

			dialogDisposeCallBack && dialogDisposeCallBack(this);
			GeneralUtils.cleanAndDisposeTarget(dialogContainer);
			dialogAnimation && dialogAnimation.dispose();
			allDialogDisposeCallBackVector = null;
			sortCurrentDialogToTopCallBack = null;
			dialogDisposeCallBack = null;
		}

		//=================================================//
		//==					       			      Private Function                                        ==//
		//=================================================//

		private function onOpenDialogAnimationFinisehd():void
		{
			onShow();
		}

		private function onCloseDialogAnimationFinished():void
		{
			disposeDialog();
		}

		private function addDialogListener():void
		{
			GeneralUtils.addTargetEventListener(dialogContainer, MouseEvent.MOUSE_DOWN, onDialogContainerMouseDown);
			GeneralUtils.addTargetEventListener(dragToMoveContainer, MouseEvent.MOUSE_DOWN, onMouseDown);
		}

		private function removeDialogListener():void
		{
			GeneralUtils.removeTargetEventListener(dialogContainer, MouseEvent.MOUSE_DOWN, onDialogContainerMouseDown);
			GeneralUtils.removeTargetEventListener(dragToMoveContainer, MouseEvent.MOUSE_DOWN, onMouseDown);
			GeneralUtils.removeTargetEventListener(dialogContainer.stage, MouseEvent.MOUSE_MOVE, onMouseMove);
			GeneralUtils.removeTargetEventListener(dialogContainer.stage, MouseEvent.MOUSE_UP, onMouseUp);
		}

		private function onMouseDown(e:MouseEvent):void
		{
			dragToMoveOffsetX = e.stageX - dialogContainer.x;
			dragToMoveOffsetY = e.stageY - dialogContainer.y;

			GeneralUtils.addTargetEventListener(dialogContainer.stage, MouseEvent.MOUSE_MOVE, onMouseMove);
			GeneralUtils.addTargetEventListener(dialogContainer.stage, MouseEvent.MOUSE_UP, onMouseUp);
		}

		private function onMouseUp(e:MouseEvent):void
		{
			GeneralUtils.removeTargetEventListener(dialogContainer.stage, MouseEvent.MOUSE_MOVE, onMouseMove);
			GeneralUtils.removeTargetEventListener(dialogContainer.stage, MouseEvent.MOUSE_UP, onMouseUp);
		}

		private function onMouseMove(e:MouseEvent):void
		{
			dialogContainer.x = e.stageX - dragToMoveOffsetX;
			dialogContainer.y = e.stageY - dragToMoveOffsetY;
			doOnDialogContainerMove();
			e.updateAfterEvent();
		}

		private function onDialogContainerMouseDown(e:MouseEvent):void
		{
			sortCurrentDialogToTopCallBack(dialogContainer);
		}

		//=================================================//
		//==									Override able Function                                    ==//
		//=================================================//

		protected function initialize():void
		{
		}

		protected function onShow():void
		{
		}

		protected function doDispose():void
		{
		}

		/**
		 * <b>Override该函数，如果ChildClass需要在Scene大小发生改变时候做一些操作</b>
		 */
		protected function doOnScreenResize(_currenStageWidth:int,
											_currentStageHeight:int,
											_offestWidth:int,
											_offestHeight:int,
											_offsetXPercent:Number,
											_offsetYPercent:Number):void
		{
		}

		/**
		 * <b>当Dialog的位置发生变化时候调用该函数</b>
		 * <li>CEDialogGroupPopWarp#layoutAllDialogByWarp会改变Dialog的位置
		 * <li>CEDialog#onMouseMove会改变Dialog位置
		 */
		protected function doOnDialogContainerMove():void
		{
		}



		/**
		 *<b>取得Dialog中会响应拖拽移动窗口事件的区域</b>
		 * </br>当鼠标在响应拖拽区域MouseDown后及可以拖拽Dialog,
		 * 如果当前Dialog不可以拖拽及返回null
		 */
		protected function getDialogDragToMoveContainer():DisplayObject
		{
			return null;
		}

		/**
		 *为每个Dialog面板生成UniqueName,
		 * 默认使用当前Dialog的类名做唯一值(UniqueName用于DialogManger中控制Dialog)
		 */
		protected function crateDialogUniqueName():String
		{
			var type:Type = Type.forInstance(this);
			return type.fullName;
		}

		public final function getDialogUniqueName():String
		{
			if (dialogUniqueName == null)
			{
				dialogUniqueName = crateDialogUniqueName();
			}
			return dialogUniqueName;
		}


	}
}
